﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Mail;
using System.Xml.Linq;
using Dexter.Async.Services;
using Dexter.Domain.Model;
using Dexter.Logger.Contracts;
using Dexter.Repository;
using Dexter.Storage;

namespace Dexter.Services.Implementation {
	public class CommentExport : ICommentExport {
		readonly IAsyncService asyncService;
		readonly IConfigurationService configurationService;
		readonly IEmailService emailService;
		readonly IEmailTemplateService emailTemplateService;
		readonly IInboxRepository inboxRepository;
		readonly ILogger logger;
		readonly IStorageProvider storageProvider;
		readonly IUrlBuilder urlBuilder;

		public CommentExport(IUrlBuilder urlBuilder, IEmailTemplateService emailTemplateService, IInboxRepository inboxRepository, IConfigurationService configurationService, IEmailService emailService, IAsyncService asyncService, IStorageProvider storageProvider, ILogger logger) {
			this.urlBuilder = urlBuilder;
			this.emailTemplateService = emailTemplateService;
			this.inboxRepository = inboxRepository;
			this.configurationService = configurationService;
			this.emailService = emailService;
			this.asyncService = asyncService;
			this.storageProvider = storageProvider;
			this.logger = logger;
		}

		#region ICommentExport Members

		public void GenerateDisqusXml(IEnumerable<Comment> comments) {
			DisqusXml(comments);
		}

		public void GenerateDisqusXmlAsync(IEnumerable<Comment> comments) {
			asyncService.AsyncCall(DisqusXml, comments);
		}

		#endregion

		void DisqusXml(object state) {
			IEnumerable<Comment> comments = (IEnumerable<Comment>) state;

			XNamespace contentNs = "http://purl.org/rss/1.0/modules/content/";
			XNamespace dsqNs = "http://www.disqus.com/";
			XNamespace wpNs = "http://wordpress.org/export/1.0/";

			XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
			XElement rss = new XElement("rss", new XAttribute("version", "2.0"),
			                            new XAttribute(XNamespace.Xmlns + "content", "http://purl.org/rss/1.0/modules/content/"),
			                            new XAttribute(XNamespace.Xmlns + "dsq", "http://www.disqus.com/"),
			                            new XAttribute(XNamespace.Xmlns + "dc", "http://purl.org/dc/elements/1.1/"),
			                            new XAttribute(XNamespace.Xmlns + "wp", "http://wordpress.org/export/1.0/"));

			XElement channel = new XElement("channel");

			doc.Add(rss);
			rss.Add(channel);

			foreach (Comment c in comments) {
				XElement item = new XElement("item");

				channel.Add(item);

				XElement title = new XElement("title", c.Item.Title);
				XElement link = new XElement("link", urlBuilder.Post.Detail(c.Item));
				XElement content = new XElement(contentNs + "encoded", c.Item.FormattedBody);
				XElement threadIdentifier = new XElement(dsqNs + "thread_identifier", c.Item.Slug);
				XElement postDateGmt = new XElement(wpNs + "post_date_gmt", c.Item.PublishDate.ToUniversalTime().ToString("yyyy-MM-dd hh:mm:ss"));
				XElement commentStatus = new XElement(wpNs + "comment_status", c.Item.CommentEnabled
				                                                               	? "open"
				                                                               	: "closed");

				XElement comment = new XElement(wpNs + "comment");

				item.Add(title, link, content, threadIdentifier, postDateGmt, commentStatus, comment);

				XElement commentId = new XElement(wpNs + "comment_id", c.Id);
				XElement commentAuthor = new XElement(wpNs + "comment_author", c.Name);
				XElement commentAuthorEmail = new XElement(wpNs + "comment_author_email", c.Email);
				XElement commentAuthorUrl = new XElement(wpNs + "comment_author_url", c.WebSite);
				XElement commentAuthorDateTimeGmt = new XElement(wpNs + "comment_date_gmt", c.CreationDate.ToUniversalTime().ToString("yyyy-MM-dd hh:mm:ss"));
				XElement commentContent = new XElement(wpNs + "comment_content", c.Message);
				XElement commentApproved = new XElement(wpNs + "comment_approved", c.Approved
				                                                                   	? "1"
				                                                                   	: "0");

				comment.Add(commentId, commentAuthor, commentAuthorEmail, commentAuthorUrl, commentAuthorDateTimeGmt, commentContent, commentApproved);

				if (c.Parent != null) {
					XElement commentParent = new XElement(wpNs + "comment_parent", c.Parent.Id);
					comment.Add(commentParent);
				}
			}

			using (MemoryStream ms = new MemoryStream()) {
				doc.Save(ms);
				storageProvider.SaveStream(storageProvider.Combine(storageProvider.PrivateRoot, "/disqusExport.xml"), ms);
			}


			EmailMessage mailMessage = GetMailMessage();

			if (mailMessage != null) {
				InboxMessage inboxMessage = new InboxMessage(mailMessage.Sender.DisplayName, mailMessage.Sender.Address, mailMessage.Subject, mailMessage.Body);

				inboxRepository.Add(inboxMessage);
				emailService.Queue(mailMessage);
			}
			else {
				SiteConfiguration configuration = configurationService.Configuration;

				string message = string.Format("Disqus comment export file generated. Download it here: {0}", urlBuilder.Export.CommentExportXml("disqusExport.xml"));

				InboxMessage inboxMessage = new InboxMessage("Dexter Notification", configuration.NotificationConfiguration.SenderEmail.ToString(), "Disqus export Complete", message);

				inboxRepository.Add(inboxMessage);
			}
		}

		EmailMessage GetMailMessage() {
			try {
				const string TEMPLATE_NAME = "dexter.notification.DiqusExportComplete";

				SiteConfiguration configuration = configurationService.Configuration;

				IEmailTemplate template = emailTemplateService.GetTemplate(TEMPLATE_NAME);

				if (template == null) {
					logger.WarnFormat("Template '{0}' not found.", TEMPLATE_NAME);
					return null;
				}

				IDictionary<string, string> values = new Dictionary<string, string> {};

				string subject = template.GetFormatedSubject(values);
				string body = template.GetFormatedBody(values);

				MailAddress email = new MailAddress(configuration.NotificationConfiguration.NotificationEmailAddress, configuration.NotificationConfiguration.NotificationEmailAddress);

				EmailMessage resultEmail = EmailMessage.CreateNewEmailMessage(configuration.NotificationConfiguration.SenderEmail, email, subject, body);

				return resultEmail;
			}
			catch (Exception e) {
				logger.Error(e.Message, e);
				return null;
			}
		}
	}
}